package icu.zhhll.util.io;

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.binary.StringUtils;

import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.security.MessageDigest;
import java.text.DecimalFormat;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;

/**
 * 文件操作
 *
 * @author zh
 * @date 2023/8/10 15:46
 */
public class FileUtils {
    /**
     * 定义GB的计算常量
     */
    private static final int GB = 1024 * 1024 * 1024;
    /**
     * 定义MB的计算常量
     */
    private static final int MB = 1024 * 1024;
    /**
     * 定义KB的计算常量
     */
    private static final int KB = 1024;

    /**
     * 格式化小数
     */
    private static final DecimalFormat DF = new DecimalFormat("0.00");

    /**
     * 下载文件
     *
     * @param fileUrl 文件地址
     * @param path    保存目录
     * @return 文件完整路径
     */
    public static String downloadFromNet(String fileUrl, String path) {
        String fileName = fileUrl.substring(fileUrl.lastIndexOf(File.separator) + 1);
        return downloadFromNet(fileUrl, path, fileName);
    }

    /**
     * 下载文件
     *
     * @param fileUrl  文件地址
     * @param path     保存目录
     * @param fileName 存储文件名称
     * @return
     */
    public static String downloadFromNet(String fileUrl, String path, String fileName) {

        InputStream inStream = null;
        try {
            URL url = new URL(fileUrl);
            URLConnection conn = url.openConnection();
            inStream = conn.getInputStream();
            File pathFile = new File(path);
            if (!pathFile.exists()) {
                pathFile.mkdir();
            }
            if (!path.endsWith(File.separator)) {
                path = path + File.separator;
            }
            File file = new File(path + fileName);
            if (!file.exists()) {
                file.createNewFile();
            }

            try (FileOutputStream fs = new FileOutputStream(file)) {
                byte[] buffer = new byte[1024];

                int byteread;
                while ((byteread = inStream.read(buffer)) != -1) {
                    fs.write(buffer, 0, byteread);
                }
            }

            return file.getAbsolutePath();

        } catch (IOException e) {
            throw new RuntimeException("文件下载失败", e);
        } finally {
            if (inStream != null) {
                try {
                    inStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    /**
     * 文件复制
     *
     * @param fromFile
     * @param toFile
     * @throws IOException
     */
    public static void copyFile(String fromFile, String toFile) throws IOException {
        try (FileInputStream in = new FileInputStream(fromFile);
             FileOutputStream out = new FileOutputStream(toFile)) {
            byte[] b = new byte[1024];
            int len;
            while ((len = in.read(b)) != -1) {
                out.write(b, 0, len);
            }
        }
    }

    /**
     * 文件读取
     *
     * @param fileName
     * @return
     * @throws IOException
     */
    public static String read(String fileName) throws IOException {
        return read(new File(fileName));
    }

    /**
     * 文件读取
     *
     * @param file
     * @return
     * @throws IOException
     */
    public static String read(File file) throws IOException {
        String fileContent;
        try (FileInputStream in = new FileInputStream(file)) {
            fileContent = read(in);
        }
        return fileContent;
    }

    /**
     * 文件读取
     *
     * @param is
     * @return
     * @throws IOException
     */
    public static String read(InputStream is) throws IOException {
        byte[] result = readBytes(is);
        return new String(result, StandardCharsets.UTF_8);
    }

    /**
     * 文件读取
     *
     * @param fileName
     * @return
     * @throws IOException
     */
    public static byte[] readBytes(String fileName) throws IOException {
        try (InputStream is = new FileInputStream(fileName)) {
            return readBytes(is);
        }

    }

    /**
     * 文件读取
     *
     * @param file
     * @return
     * @throws IOException
     */
    public static byte[] readBytes(File file) throws IOException {
        try (InputStream is = new FileInputStream(file)) {
            return readBytes(is);
        }
    }

    /**
     * 文件读取
     *
     * @param is
     * @return
     * @throws IOException
     */
    public static byte[] readBytes(InputStream is) throws IOException {
        if (is == null || is.available() < 1) {
            return null;
        }
        ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
        byte[] buff = new byte[1024];
        int rc;
        while ((rc = is.read(buff, 0, 1024)) > 0) {
            swapStream.write(buff, 0, rc);
        }
        return swapStream.toByteArray();
    }

    /**
     * 文件写入
     *
     * @param content
     * @param file
     * @throws IOException
     */
    public static void write(String content, File file) throws IOException {
        write(content.getBytes(StandardCharsets.UTF_8), file);
    }

    /**
     * 文件写入
     *
     * @param content
     * @param file
     * @throws IOException
     */
    public static void write(String content, String file) throws IOException {
        write(content, new File(file));
    }

    /**
     * 文件写入
     *
     * @param bytes
     * @param file
     * @throws IOException
     */
    public static void write(byte[] bytes, String file) throws IOException {
        write(bytes, new File(file));
    }

    /**
     * 文件写入
     *
     * @param bytes
     * @param file
     * @throws IOException
     */
    public static void write(byte[] bytes, File file) throws IOException {
        try (FileOutputStream out = new FileOutputStream(file)) {
            out.write(bytes);
            out.flush();
        }
    }

    /**
     * 删除文件
     *
     * @param fileName
     * @throws IOException
     */
    public static void deleteFile(String fileName) throws IOException {
        File file = new File(fileName);
        if (file.exists()) {
            deleteFile(file);
        }
    }

    /**
     * 删除文件
     *
     * @param file
     * @throws IOException
     */
    public static void deleteFile(File file) throws IOException {
        Files.delete(file.toPath());

        if (file.exists()) {
            file.deleteOnExit();
        }
    }

    /**
     * 删除目录 递归删除
     *
     * @param dir
     * @return
     */
    public static boolean deleteDir(File dir) {
        boolean hasDeleted = true;
        File[] allFiles = dir.listFiles();
        // 删除目录下文件
        if (allFiles != null && allFiles.length > 0) {
            for (int i = 0; i < allFiles.length && hasDeleted; ++i) {
                if (allFiles[i].isDirectory()) { // 递归删除
                    hasDeleted = deleteDir(allFiles[i]);
                } else if (allFiles[i].isFile()) {
                    try {
                        Files.delete(allFiles[i].toPath());
                    } catch (IOException | SecurityException ex2) {
                        hasDeleted = false;
                    }
                }
            }
        }

        if (hasDeleted) {
            try {
                Files.delete(dir.toPath());
            } catch (IOException e2) {
                hasDeleted = false;
            }
        }
        return hasDeleted;
    }

    /**
     * 打成jar包
     *
     * @param archiveFile
     * @param tobeJared
     * @throws IOException
     */
    public static void createJarArchive(File archiveFile, File[] tobeJared) throws IOException {
        byte[] buffer = new byte[1024];
        try (FileOutputStream stream = new FileOutputStream(archiveFile);
             JarOutputStream out = new JarOutputStream(stream, new Manifest())) {
            for (File file : tobeJared) {
                if (file != null && file.exists()) {
                    if (!file.isDirectory()) {
                        JarEntry jarAdd = new JarEntry(file.getName());
                        jarAdd.setTime(file.lastModified());
                        out.putNextEntry(jarAdd);
                        try (FileInputStream in = new FileInputStream(file)) {
                            while (true) {
                                int nRead = in.read(buffer, 0, buffer.length);
                                if (nRead <= 0) {
                                    break;
                                }
                                out.write(buffer, 0, nRead);
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 获取文件后缀
     *
     * @param src 文件路径/名称 文件路径 C:\Users\Public\Pictures\Sample Pictures\test.jpg
     * @return 如果文件后缀 jpg
     */
    public static String getFileExt(String src) {

        String filename = src.substring(src.lastIndexOf(File.separator) + 1);// 获取到文件名

        return filename.substring(filename.lastIndexOf(".") + 1);
    }

    /**
     * 获取文件名称，不带文件后缀部分
     *
     * @param src 文件路径 C:\Users\Public\Pictures\Sample Pictures\test.jpg
     * @return 文件名称 不带文件后缀 test
     */
    public static String getFileName(String src) {

        String filename = src.substring(src.lastIndexOf(File.separator) + 1);// 获取到文件名

        return filename.substring(0, filename.lastIndexOf("."));
    }

    /**
     * 文件大小转换
     */
    public static String getSize(long size) {
        String resultSize;
        if (size / GB >= 1) {
            //如果当前Byte的值大于等于1GB
            resultSize = DF.format(size / (float) GB) + "GB";
        } else if (size / MB >= 1) {
            //如果当前Byte的值大于等于1MB
            resultSize = DF.format(size / (float) MB) + "MB";
        } else if (size / KB >= 1) {
            //如果当前Byte的值大于等于1KB
            resultSize = DF.format(size / (float) KB) + "KB";
        } else {
            resultSize = size + "B";
        }
        return resultSize;
    }

    /**
     * 获取一个文件的md5值(可处理大文件)
     *
     * @return md5 value
     */
    public static String getMD5(File file) {

        try (FileInputStream fileInputStream = new FileInputStream(file);) {
            MessageDigest MD5 = MessageDigest.getInstance("MD5");
            byte[] buffer = new byte[8192];
            int length;
            while ((length = fileInputStream.read(buffer)) != -1) {
                MD5.update(buffer, 0, length);
            }
            return new String(Hex.encodeHex(MD5.digest()));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 判断两个文件是否相同
     */
    public static boolean check(File file1, File file2) {
        String file1Md5 = getMD5(file1);
        String file2Md5 = getMD5(file2);
        return check(file1Md5, file2Md5);
    }

    /**
     * 判断两个文件是否相同
     */
    public static boolean check(String file1Md5, String file2Md5) {
        return StringUtils.equals(file1Md5, file2Md5);
    }

    /**
     * 获取文件类型
     *
     * @param type
     * @return
     */
    public static FileType getFileType(String type) {
        String documents = "txt doc pdf ppt pps xlsx xls docx";
        String audio = "mp3 wav wma mpa ram ra aac aif m4a";
        String video = "avi mpg mpe mpeg asf wmv mov qt rm mp4 flv m4v webm ogv ogg";
        String image = "bmp dib pcp dif wmf gif jpg tif eps psd cdr iff tga pcd mpt png jpeg";
        if (image.contains(type)) {
            return FileType.IMAGE;
        } else if (documents.contains(type)) {
            return FileType.TXT;
        } else if (audio.contains(type)) {
            return FileType.AUDIO;
        } else if (video.contains(type)) {
            return FileType.VIDEO;
        } else {
            return FileType.OTHER;
        }
    }

    /**
     * 文件类型
     */
    public enum FileType {
        IMAGE,
        TXT,
        AUDIO,
        VIDEO,
        OTHER;
    }
}
